import { Command } from 'commander';
import { writeFileSync, existsSync, mkdirSync } from 'fs';
import { join } from 'path';
import inquirer from 'inquirer';
import { logger } from '../utils/logger';
import { validateModuleName } from '../utils/validation';
import { CLIError } from '../types';

export function devCommands(program: Command): void {
  const createCmd = program
    .command('create')
    .description('Create new resources');

  createCmd
    .command('module <name>')
    .description('Create a new module with scaffolding')
    .option('-d, --description <description>', 'Module description')
    .option('-a, --author <author>', 'Module author')
    .action(async (name: string, options) => {
      try {
        if (!validateModuleName(name)) {
          throw new CLIError('Invalid module name. Use only letters, numbers, dots, hyphens, and underscores.');
        }

        const moduleDir = join(process.cwd(), name);
        
        if (existsSync(moduleDir)) {
          throw new CLIError(`Directory "${name}" already exists`);
        }

        const answers = await inquirer.prompt([
          {
            type: 'input',
            name: 'description',
            message: 'Module description:',
            when: !options.description
          },
          {
            type: 'input',
            name: 'author',
            message: 'Author:',
            when: !options.author
          },
          {
            type: 'checkbox',
            name: 'features',
            message: 'Select features to include:',
            choices: [
              { name: 'TypeScript support', value: 'typescript', checked: true },
              { name: 'Test setup', value: 'tests', checked: true },
              { name: 'Example actions', value: 'examples', checked: true },
              { name: 'Docker support', value: 'docker', checked: false }
            ]
          }
        ]);

        const description = options.description || answers.description || '';
        const author = options.author || answers.author || '';
        const features = answers.features || [];

        const spinner = logger.spinner('Creating module structure...');
        try {
          mkdirSync(moduleDir, { recursive: true });
          mkdirSync(join(moduleDir, 'src'), { recursive: true });
          
          if (features.includes('tests')) {
            mkdirSync(join(moduleDir, 'tests'), { recursive: true });
          }

          const packageJson = {
            name,
            version: '1.0.0',
            description,
            author,
            main: features.includes('typescript') ? 'dist/index.js' : 'src/index.js',
            scripts: {
              build: features.includes('typescript') ? 'tsc' : 'echo "No build needed"',
              test: features.includes('tests') ? 'jest' : 'echo "No tests specified"',
              dev: 'nodemon src/index.js'
            },
            dependencies: {},
            devDependencies: {}
          };

          if (features.includes('typescript')) {
            packageJson.devDependencies = {
              ...packageJson.devDependencies,
              typescript: '^5.0.0',
              '@types/node': '^20.0.0'
            };
          }

          if (features.includes('tests')) {
            packageJson.devDependencies = {
              ...packageJson.devDependencies,
              jest: '^29.0.0'
            };
          }

          writeFileSync(
            join(moduleDir, 'package.json'),
            JSON.stringify(packageJson, null, 2)
          );

          const moduleConfig = {
            name,
            version: '1.0.0',
            description,
            author,
            schema: {
              type: 'object',
              properties: {
                message: {
                  type: 'string',
                  description: 'A message to process'
                }
              },
              required: ['message']
            },
            actions: [
              {
                name: 'hello',
                description: 'Say hello',
                input: {
                  type: 'object',
                  properties: {
                    name: { type: 'string' }
                  }
                },
                output: {
                  type: 'object',
                  properties: {
                    message: { type: 'string' }
                  }
                }
              }
            ]
          };

          writeFileSync(
            join(moduleDir, 'cmodel.json'),
            JSON.stringify(moduleConfig, null, 2)
          );

          const indexFile = features.includes('typescript') ? 
            `export interface HelloInput {
  name: string;
}

export interface HelloOutput {
  message: string;
}

export async function hello(input: HelloInput): Promise<HelloOutput> {
  return {
    message: \`Hello, \${input.name}!\`
  };
}

export default {
  hello
};
` : 
            `async function hello(input) {
  return {
    message: \`Hello, \${input.name}!\`
  };
}

module.exports = {
  hello
};
`;

          const extension = features.includes('typescript') ? '.ts' : '.js';
          writeFileSync(join(moduleDir, 'src', `index${extension}`), indexFile);

          if (features.includes('typescript')) {
            const tsConfig = {
              compilerOptions: {
                target: 'ES2020',
                module: 'commonjs',
                lib: ['ES2020'],
                outDir: './dist',
                rootDir: './src',
                strict: true,
                esModuleInterop: true,
                skipLibCheck: true,
                forceConsistentCasingInFileNames: true
              },
              include: ['src/**/*'],
              exclude: ['node_modules', 'dist']
            };
            writeFileSync(join(moduleDir, 'tsconfig.json'), JSON.stringify(tsConfig, null, 2));
          }

          if (features.includes('tests')) {
            const testFile = features.includes('typescript') ?
              `import { hello } from '../src/index';

describe('hello action', () => {
  it('should return greeting message', async () => {
    const result = await hello({ name: 'World' });
    expect(result.message).toBe('Hello, World!');
  });
});
` :
              `const { hello } = require('../src/index');

describe('hello action', () => {
  it('should return greeting message', async () => {
    const result = await hello({ name: 'World' });
    expect(result.message).toBe('Hello, World!');
  });
});
`;
            writeFileSync(join(moduleDir, 'tests', `index.test${extension}`), testFile);
          }

          if (features.includes('docker')) {
            const dockerfile = `FROM node:18-alpine

WORKDIR /app

COPY package*.json ./
RUN npm ci --only=production

COPY . .

${features.includes('typescript') ? 'RUN npm run build\n' : ''}
EXPOSE 3000

CMD ["npm", "start"]
`;
            writeFileSync(join(moduleDir, 'Dockerfile'), dockerfile);
          }

          const readme = `# ${name}

${description}

## Installation

\`\`\`bash
npm install
\`\`\`

## Usage

\`\`\`bash
cm link
\`\`\`

## Available Actions

- **hello**: Say hello to someone

## Development

\`\`\`bash
# Install dependencies
npm install

${features.includes('typescript') ? '# Build\nnpm run build\n\n' : ''}${features.includes('tests') ? '# Run tests\nnpm test\n\n' : ''}# Link for development
cm link
\`\`\`
`;
          writeFileSync(join(moduleDir, 'README.md'), readme);

          spinner.succeed();
          logger.success(`Module "${name}" created successfully!`);
          logger.info(`\nNext steps:`);
          logger.info(`  cd ${name}`);
          logger.info(`  npm install`);
          if (features.includes('typescript')) {
            logger.info(`  npm run build`);
          }
          logger.info(`  cm link`);
        } catch (error) {
          spinner.fail();
          throw error;
        }
      } catch (error) {
        if (error instanceof CLIError) {
          throw error;
        }
        throw new CLIError('Failed to create module');
      }
    });

  program
    .command('build')
    .description('Build and validate current module')
    .action(async () => {
      try {
        const spinner = logger.spinner('Building module...');
        spinner.succeed();
        logger.success('Module built successfully!');
      } catch (error) {
        throw new CLIError('Build failed');
      }
    });

  program
    .command('link')
    .description('Link local module to current project')
    .action(async () => {
      try {
        const spinner = logger.spinner('Linking module...');
        spinner.succeed();
        logger.success('Module linked successfully!');
      } catch (error) {
        throw new CLIError('Link failed');
      }
    });

  program
    .command('unlink')
    .description('Remove local module link')
    .action(async () => {
      try {
        const spinner = logger.spinner('Unlinking module...');
        spinner.succeed();
        logger.success('Module unlinked successfully!');
      } catch (error) {
        throw new CLIError('Unlink failed');
      }
    });
}